package com.hex.ds.hdrs.center.service;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.hex.ds.hdrs.agent.po.AgentConf;
import com.hex.ds.hdrs.agent.service.AgentConfService;
import com.hex.ds.hdrs.agent.service.AgentSession;
import com.hex.ds.hdrs.center.po.CenterConf;
import com.hex.ds.hdrs.common.constant.Const;
import com.hex.ds.hdrs.common.enums.CronTaskDefStatusEnum;
import com.hex.ds.hdrs.cron.dto.CronTaskDefDto;
import com.hex.ds.hdrs.cron.po.CronTaskDef;
import com.hex.ds.hdrs.cron.service.CronService;
import com.hex.ds.hdrs.cron.service.CronTaskDefService;
import com.hex.ds.hdrs.engine.service.DispatcherService;
import com.hex.ds.hdrs.engine.service.LoaderService;
import com.hex.ds.hdrs.engine.service.ProcessorService;
import com.hex.ds.hdrs.period.job.po.JobTask;
import com.hex.ds.hdrs.period.job.service.QueueJobInfService;
import com.hex.ds.hdrs.period.task.dto.TaskInfo;
import com.hex.ds.hdrs.period.task.service.TaskFinishService;
import com.hex.ds.hdrs.period.task.vo.CycleTaskReq;
import com.hex.ds.hdrs.watch.service.WatchService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @Package: com.hex.ds.hdrs.center.service
 * @ClassName CenterService
 * @Description: 中心处理 逻辑
 * @Author: jd.chen
 * @Date 2021/7/5 19:59
 * @Version v1.0
 **/
@Slf4j
@Service
public class CenterService {

    @Autowired
    private CenterConfService centerConfService;

    @Autowired
    private AgentConfService agentConfService;

    @Autowired
    private MasterCenterInfoService masterCenterInfoService;

    @Autowired
    private TaskFinishService taskFinishService;

    @Autowired
    private QueueJobInfService queueJobInfService;

    @Autowired
    private WatchService watchService;

    @Autowired
    private LoaderService loaderService;

    @Autowired
    private ProcessorService processorService;

    @Autowired
    private DispatcherService dispatcherService;

    @Autowired
    private CronTaskDefService cronTaskDefService;

    @Autowired
    private CronService cronService;

    private static final byte[] jobTaskListSyn = {};

    /**
     * @Method: agentLoginNotice
     * @Param: [agentSession]
     * @Return: void
     * @Description： 邮件发送
     * @Author： jd.chen
     * @Date： 2021/7/5 19:27
     * @Version： V1.0
     */
    public void agentLoginNotice(AgentSession agentSession){
        watchService.agentLoginNotice(agentSession.getAgentConf());
    }

    /**
     * @Method: updateAgentStatus
     * @Param: [agentCode]
     * @Return: void
     * @Description： 更新节点状态 -- 暂停
     * @Author： jd.chen
     * @Date： 2021/7/5 19:29
     * @Version： V1.0
     */
    public void updateAgentStatus(String agentCode){
        Map map = new HashMap();
        map.put("agentStatus", Const.AGENT_STATUS_STOP);
        map.put("agentCode", agentCode);
        agentConfService.updateAgentStatus(map);
    }

    /**
     * @Method: updateAgentLstTime
     * @Param: [agentCode]
     * @Return: void
     * @Description： 更新agentSession 最新心跳时间
     * @Author： jd.chen
     * @Date： 2021/7/5 19:31
     * @Version： V1.0
     */
    public void updateAgentLstTime(String agentCode){
        Map map = new HashMap();
        map.put("lastReceveTime", DateUtil.now());
        map.put("agentHaStatus", Const.AGENT_HA_STATUS_NORMAL);
        map.put("agentCode",agentCode);
        this.agentConfService.updateAgentLstTime(map);
    }

    /**
     * @Method: cycleTaskExecBack
     * @Param: [req]
     * @Return: void
     * @Description：  周期任务结果处理
     * @Author： jd.chen
     * @Date： 2021/7/5 19:33
     * @Version： V1.0
     */
    public void cycleTaskExecBack(CycleTaskReq req){
        this.taskFinishService.cycleTaskExecBack(req);
    }

    /**
     * @Method: cronTaskExecBack
     * @Param: []
     * @Return: void
     * @Description： 定时任务结果处理
     * @Author： jd.chen
     * @Date： 2021/7/5 19:34
     * @Version： V1.0
     */
    public void cronTaskExecBack(TaskInfo taskInfo){
        this.taskFinishService.cronTaskExecBack(taskInfo);
    }

    /**
     * @Method: loaderInit
     * @Param: []
     * @Return: void
     * @Description： 加载器初始化
     * @Author： jd.chen
     * @Date： 2021/7/5 19:36
     * @Version： V1.0
     */
    public void loaderInit(){
        loaderService.init();
    }

    /**
     * @Method: processorInit
     * @Param: []
     * @Return: void
     * @Description： 处理器初始化
     * @Author： jd.chen
     * @Date： 2021/7/5 19:37
     * @Version： V1.0
     */
    public void processorInit(){
        processorService.init();
    }

    /**
     * @Method: dispatcherInit
     * @Param: []
     * @Return: void
     * @Description： 分发器初始化
     * @Author： jd.chen
     * @Date： 2021/7/5 19:37
     * @Version： V1.0
     */
    public void dispatcherInit(){
        dispatcherService.init();
    }

    /**
     * @Method: cronTaskEngineInit
     * @Param: []
     * @Return: void
     * @Description： 定时任务定义初始化
     * @Author： jd.chen
     * @Date： 2021/7/5 19:39
     * @Version： V1.0
     */
    public void cronTaskEngineInit(){
        try {
            List<CronTaskDef> cronTaskDefList = cronTaskDefService.queryList(new CronTaskDefDto().setTaskStatus(CronTaskDefStatusEnum.ENABLE.getName()));
            for (CronTaskDef cronTaskDef : cronTaskDefList) {
                if ("2".equals(cronTaskDef.getIsValidDate()) || (checkTaskStDate(cronTaskDef) && checkTaskEndDate(cronTaskDef))){
                    cronService.add(cronTaskDef);
                }
            }
        } catch (Exception e) {
            log.error("定时任务初始化处理异常:{}", e.getMessage(), e);

        }
    }

    /*
     * @Method: checkTaskStDate <br>
     * @Param: [cronTaskDef] <br>
     * @Return: boolean <br>
     * @Description：定时任务定义有效期开始日期判断<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/3 15:33 <br>
     * @Version： V2.0.2<br>
     */
    private boolean checkTaskStDate(CronTaskDef cronTaskDef){
        return StrUtil.isNotBlank(cronTaskDef.getTaskStDate()) && cn.hutool.core.date.DateUtil.date().isAfterOrEquals(cn.hutool.core.date.DateUtil.parseDate(cronTaskDef.getTaskStDate()));
    }

    /*
     * @Method: checkTaskEndDate <br>
     * @Param: [cronTaskDef] <br>
     * @Return: boolean <br>
     * @Description：定时任务定义有效期结束日期判断<br>
     * @Author： wz.li<br>
     * @Date： 2023/4/3 15:34 <br>
     * @Version： V2.0.2<br>
     */
    private boolean checkTaskEndDate(CronTaskDef cronTaskDef){
        return StrUtil.isNotBlank(cronTaskDef.getTaskEndDate()) && cn.hutool.core.date.DateUtil.date().isBeforeOrEquals(cn.hutool.core.date.DateUtil.parseDate(cronTaskDef.getTaskEndDate()));
    }

    /**
     * @Method: centerSwitchNotic
     * @Param: [centerName]
     * @Return: void
     * @Description： 中心切换，邮件通知
     * @Author： jd.chen
     * @Date： 2021/7/5 19:40
     * @Version： V1.0
     */
    public void centerSwitchNotic(String centerName){
        watchService.centerSwitchNotic(centerName);
    }

    /**
     * @Method: closeProcess
     * @Param: []
     * @Return: void
     * @Description： 关闭处理器
     * @Author： jd.chen
     * @Date： 2021/7/5 19:41
     * @Version： V1.0
     */
    public void closeProcess(){
        processorService.closeProcess();
    }

    /**
     * @Method: closeDispatcher
     * @Param: []
     * @Return: void
     * @Description： 关闭分发器
     * @Author： jd.chen
     * @Date： 2021/7/5 19:42
     * @Version： V1.0
     */
    public void closeDispatcher(){
        dispatcherService.closeDispatcher();
    }


    /**
     * 通过ip获取中心配置
     *
     * @param ip
     * @return
     */
    public CenterConf getCenterConf(String ip) {
        Map map = new HashMap();
        map.put("centerIp", ip);
        return centerConfService.qry(map);
    }

    /**
     * 初始化master
     *
     * @param centerConf
     */
    public void initMaster(CenterConf centerConf) {
        log.info("初始化master【CenterService.initMaster】");
        if (null == masterCenterInfoService.qry()) {
            Map map = new HashMap();
            map.put("centerIp", centerConf.getCenterIp());
            map.put("centerCode", centerConf.getCenterCode());
            map.put("centerGroup", centerConf.getCenterGroup());
            map.put("validAgentNum", centerConf.getValidAgentNum());
            masterCenterInfoService.add(map);
        }
    }

    /**
     * 成为 master
     *
     * @param centerCode
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void toMaster(String centerCode) {
        log.info("成为 master【CenterService.toMaster】centerCode: {}" , centerCode);
        Map map = new HashMap();
        String curTs = DateUtil.now();
        map.put("centerCode", centerCode);
        map.put("centerStatus", Const.CENTER_RUN);
        map.put("isMaster", Const.IS_MASTER);
        map.put("upTs", curTs);
        map.put("toMasterTs", curTs);
        centerConfService.updateCenterConf(map);
    }

    /**
     * 从 master 休眠
     *
     * @param centerCode
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void notMaster(String centerCode) {
        log.info("从 master 休眠【CenterService.notMaster】centerCode: {}" , centerCode);
        Map map = new HashMap();
        String curTs = DateUtil.now();
        map.put("centerCode", centerCode);
        map.put("centerStatus", Const.CENTER_SLEEP);
        map.put("isMaster", Const.NOT_MASTER);
        map.put("upTs", curTs);
        map.put("loseMasterTs", curTs);
        centerConfService.updateCenterConf(map);
    }

    /**
     * @Method: otherNotMaster <br>
     * @Param: [centerCode] <br>
     * @Return: void <br>
     * @Description：其他中心下线<br>
     * @Author： gc.zuo<br>
     * @Date： 2022/6/27 15:59 <br>
     * @Version： V1.0<br>
     */
    public void otherNotMaster(String centerCode) {
        log.info("从 master 休眠【CenterService.notMaster】centerCode: {}" , centerCode);
        Map map = new HashMap();
        String curTs = DateUtil.now();
        map.put("centerCode", centerCode);
        map.put("centerStatus", Const.CENTER_SLEEP);
        map.put("isMaster", Const.NOT_MASTER);
        map.put("upTs", curTs);
        map.put("loseMasterTs", curTs);
        centerConfService.otherNotMaster(map);
    }

    /**
     * @Method: getNoMasterCenter
     * @Param: [map]
     * @Return: java.util.List<com.hex.ds.hdrs.center.po.CenterConf>
     * @Description： 获取非 master 中心
     * @Author： jd.chen
     * @Date： 2021/7/5 19:45
     * @Version： V1.0
     */
    public List<CenterConf> getNoMasterCenter(Map map) {
        return centerConfService.qryList(map);
    }

    /**
     * @Method: qryAgentConfList
     * @Param: []
     * @Return: java.util.List<com.hex.ds.hdrs.agent.po.AgentConf>
     * @Description：  获取有效的节点数
     * @Author： jd.chen
     * @Date： 2021/7/5 19:48
     * @Version： V1.0
     */
    public List<AgentConf> qryAgentConfList(){
        Map map = new HashMap();
        map.put("agentStatus", Const.AGENT_STATUS_START);
        return agentConfService.qryAgentConfList(map);
    }

    /**
     * @Method: updateCenterConf
     * @Param: [map]
     * @Return: void
     * @Description： 更新有效节点数
     * @Author： jd.chen
     * @Date： 2021/7/5 19:50
     * @Version： V1.0
     */
    public void updateCenterConf(Map map){
        centerConfService.updateCenterConf(map);
    }


    /**
     * 抢占DB
     *
     * @param centerConf
     * @param noUpDbTsLimit
     * @return
     */
    public boolean grabDb(CenterConf centerConf, int noUpDbTsLimit) {
        log.debug("抢占DB【CenterService.grabDb】========");
        Map map = new HashMap();
        map.put("centerCode", centerConf.getCenterCode());
        map.put("centerIp", centerConf.getCenterIp());
        map.put("centerGroup", centerConf.getCenterGroup());
        String plusTime = DateUtil.formatDateTime(DateUtil.offsetMinute(new Date(), -noUpDbTsLimit));
        map.put("plusTime", plusTime);
        map.put("noUpDbTsLimit", noUpDbTsLimit);
        map.put("upTs", DateUtil.now());
        return this.masterCenterInfoService.grabDb(map);
    }

    /**
     * 记录各个应用内存队列现存作业数
     */
    public void ramQueueQuantityStatisticsByAppCode(List<JobTask> jobTaskList, String type, String nowTime) {
        if (CollectionUtils.isNotEmpty(jobTaskList)) {
            this.queueJobInfService.add(Const.QUEUE_CENTER_APP_CODE, type, jobTaskList.size(), nowTime);
            Map<String, Integer> dataMap = new HashMap<>();
            synchronized (jobTaskListSyn) {
                for (JobTask jobTask : jobTaskList) {
                    if (jobTask != null) {
                        String appCode = jobTask.getAppCode();
                        Integer num = 0;
                        if (dataMap.containsKey(appCode)) {
                            num = dataMap.get(appCode);
                        }
                        dataMap.put(appCode, num + 1);
                    }
                }
            }
            for (String appCode : dataMap.keySet()) {
                Integer num = dataMap.get(appCode);
                this.queueJobInfService.add(appCode, type, num, nowTime);
            }
        }
    }

}
